package com.hp.bon.sgw.bean;

import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.hp.bon.sgw.core.InprogressMessageQueue;
import com.hp.bon.sgw.service.ConfigListener;
import com.hp.bon.sgw.service.ConfigService;
import com.hp.bon.sgw.start.SpringContext;
import com.hp.bon.sgw.util.Comutils;

/**
 * 记录系统拥塞的数据
 * 
 * @author wuzhih
 * 
 */
public class CongestionBean implements ConfigListener {

	private static CongestionBean instance;

	public static CongestionBean getInstance() {
		if (instance == null) {
			instance = SpringContext.getInstance().getCongestionBean();
		}
		return instance;
	}

	/**
	 * Logger for this class
	 */
	private static final Logger logger = LoggerFactory.getLogger(CongestionBean.class);

	private ConfigService configService;
	public static final int SYS_CROWED_NONE = 0000;
	public static final int SYS_CROWED_LIGHT = 1000;
	public static final int SYS_CROWED_SERVER = 2100;
	public static final int SYS_CROWED_DOS = 9999;

	private volatile long prevCrawedTime;
	private volatile int prevCrawedLevel;
	private volatile double prevCrawedIndex;

	private volatile long curCrawedTime;
	private volatile int curCrawedLevel;
	private volatile double curCrawedIndex;
	/**
	 * drop的能力统计，key是能力，value是drop的量
	 */
	private ConcurrentHashMap<String, Integer> dropedCapsMap = new ConcurrentHashMap<String, Integer>();

	private InprogressMessageQueue inMsgQueue;
	/**
	 * 轻度拥塞时，过滤高于以下优先级的消息
	 */
	protected volatile int lightLevelReqPriority = Integer.MAX_VALUE;

	/**
	 * 严重拥塞时，过滤高于以下优先级的消息
	 */
	protected volatile int serverLevelReqPriority = Integer.MAX_VALUE;
	/**
	 * 所关心的运行期变化的配置数据的Key
	 */
	protected final Set<String> monitorConfKeys = new HashSet<String>();

	public CongestionBean() {
		monitorConfKeys.add(SysParamBean.KEY_AGREEMENT_Congestion_Prioriy_1000_MIN);
		monitorConfKeys.add(SysParamBean.KEY_AGREEMENT_Congestion_Prioriy_2100_MIN);

	}

	public void init() {
		logger.info("load congestion priority ");
		this.loadConfCrowedPriority();
	}

	public void swap() {
		this.prevCrawedIndex = curCrawedIndex;
		this.prevCrawedLevel = curCrawedLevel;
		this.prevCrawedTime = curCrawedTime;
	}

	private void incDropCount(int priority, String sessionID, String capability) {
		if (logger.isInfoEnabled()) {
			logger.info("system congestioned, drop request ,sessionid is " + sessionID + " priority " + priority);
		}
		Integer value = dropedCapsMap.get(capability);
		value = (value == null) ? 1 : value++;
		dropedCapsMap.put(capability, value);
	}

	public long getPrevCrawedTime() {
		return prevCrawedTime;
	}

	public void setPrevCrawedTime(long prevCrawedTime) {
		this.prevCrawedTime = prevCrawedTime;
	}

	public long getCurCrawedTime() {
		return curCrawedTime;
	}

	public void setCurCrawedTime(long curCrawedTime) {
		this.curCrawedTime = curCrawedTime;
	}

	public int getPrevCrawedLevel() {
		return prevCrawedLevel;
	}

	public void setPrevCrawedLevel(int prevCrawedLevel) {
		this.prevCrawedLevel = prevCrawedLevel;
	}

	public double getPrevCrawedIndex() {
		return prevCrawedIndex;
	}

	public void setPrevCrawedIndex(double prevCrawedIndex) {
		this.prevCrawedIndex = prevCrawedIndex;
	}

	public int getCurCrawedLevel() {
		return curCrawedLevel;
	}

	public void setCurCrawedLevel(int curCrawedLevel) {
		this.curCrawedLevel = curCrawedLevel;
	}

	public double getCurCrawedIndex() {
		return curCrawedIndex;
	}

	public String getCongestLevelStr() {
		switch (this.curCrawedLevel) {
		case SYS_CROWED_NONE:
			return "NONE";
		case SYS_CROWED_LIGHT:
			return "LIGHT";
		case SYS_CROWED_SERVER:
			return "SERVE";
		case SYS_CROWED_DOS:
			return "DOS";
		default:
			return curCrawedLevel + "";
		}

	}

	public void setCurCrawedIndex(double curCrawedIndex) {
		this.curCrawedIndex = curCrawedIndex;
	}

	public boolean dropRequest(int priority, String sessionID, String capability) {
		switch (getCurCrawedLevel()) {
		case CongestionBean.SYS_CROWED_NONE:
			break;
		case CongestionBean.SYS_CROWED_LIGHT: {
			if (priority > lightLevelReqPriority) {
				incDropCount(priority, sessionID, capability);
				return true;
			}
			break;
		}
		case CongestionBean.SYS_CROWED_SERVER: {
			if (priority > serverLevelReqPriority) {
				incDropCount(priority, sessionID, capability);
				return true;
			}
			break;
		}
		case CongestionBean.SYS_CROWED_DOS: {
			incDropCount(priority, sessionID, capability);
			return true;
		}
		}
		return false;
	}

	private void loadConfCrowedPriority() {
		String param = SysParamBean.KEY_AGREEMENT_Congestion_Prioriy_1000_MIN;
		String priorty = configService.getValue(param, Integer.MAX_VALUE + "");
		if (priorty != null) {
			this.lightLevelReqPriority = Integer.valueOf(priorty);
			logger.info("param: " + param + " is set to " + lightLevelReqPriority);
		}
		param = SysParamBean.KEY_AGREEMENT_Congestion_Prioriy_2100_MIN;
		priorty = configService.getValue(param, Integer.MAX_VALUE + "");
		if (priorty != null) {
			this.serverLevelReqPriority = Integer.valueOf(priorty);
			logger.info("param: " + param + " is set to " + serverLevelReqPriority);
		}
	}

	public SGWStatCongessionBean toStatBean() {
		SGWStatCongessionBean targeBean = new SGWStatCongessionBean();
		if (this.curCrawedLevel != SYS_CROWED_NONE) {
			targeBean.setBeginCongesionTime(Comutils.formatTime(this.curCrawedTime, Comutils.GEN_DATA_FORMAT));
		}
		targeBean.setLevel(getCongestLevelStr() + " [" + this.curCrawedIndex + "]");
		int dropedCount = 0;
		Map<String, Integer> dropedMap = new LinkedHashMap<String, Integer>();
		for (Map.Entry<String, Integer> entry : this.dropedCapsMap.entrySet()) {
			int count = entry.getValue();
			dropedCount += count;
			dropedMap.put(entry.getKey(), count);
		}
		targeBean.setNeDroppedMessages(dropedMap);
		targeBean.setDroppedMessages(dropedCount);
		// 处理积压的消息队列
		Map<String, Integer> pendingMap = new LinkedHashMap<String, Integer>();
		int pendingMsgs = inMsgQueue.getCurCapsSum(pendingMap);
		targeBean.setPendingMessages(pendingMsgs);
		targeBean.setNePendingMessages(pendingMap);
		return targeBean;
	}

	@Autowired
	public void setInMsgQueue(InprogressMessageQueue inMsgQueue) {
		this.inMsgQueue = inMsgQueue;
	}

	@Autowired
	public void setConfigService(ConfigService configService) {
		this.configService = configService;
	}

	public InprogressMessageQueue getInMsgQueue() {
		return inMsgQueue;
	}

	@Override
	public Set<String> monitorConfKeys() {
		return monitorConfKeys;
	}

	@Override
	public void onConfigUpdated(String updatedKey) {
		this.loadConfCrowedPriority();

	}

}